/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jsinterfacesample.android.chrome.google.com.jsinterface_example;
import android.annotation.TargetApi;
import android.app.Fragment;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.util.JsonReader;
import android.util.JsonToken;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.ValueCallback;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import java.io.IOException;
import java.io.StringReader;
/**
* Created by mattgaunt on 10/16/14.
*/
public class MainFragment extends Fragment {
public static final String EXTRA_FROM_NOTIFICATION = "EXTRA_FROM_NOTIFICATION";
private WebView mWebView;
public MainFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
// Get reference of WebView from layout/activity_main.xml
mWebView = (WebView) rootView.findViewById(R.id.fragment_main_webview);
// Add Javascript Interface, this will expose "window.NotificationBind"
// in Javascript
mWebView.addJavascriptInterface(
new NotificationBindObject(getActivity().getApplicationContext()),
"NotificationBind");
setUpWebViewDefaults(mWebView);
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore the previous URL and history stack
mWebView.restoreState(savedInstanceState);
}
// Prepare the WebView and get the appropriate URL
String url = prepareWebView(mWebView.getUrl());
// Load the local index.html file
if(mWebView.getUrl() == null) {
mWebView.loadUrl(url);
}
return rootView;
}
/**
* Convenience method to set some generic defaults for a
* given WebView
*
* @param webView
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setUpWebViewDefaults(WebView webView) {
WebSettings settings = webView.getSettings();
// Enable Javascript
settings.setJavaScriptEnabled(true);
// Use WideViewport and Zoom out if there is no viewport defined
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
// Enable pinch to zoom without the zoom buttons
settings.setBuiltInZoomControls(true);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
// Hide the zoom controls for HONEYCOMB+
settings.setDisplayZoomControls(false);
}
// Enable remote debugging via chrome://inspect
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
}
/**
* This is method where specific logic for this application is going to live
* @return url to load
*/
private String prepareWebView(String currentUrl) {
String hash = "";
int bgColor;
if(currentUrl != null) {
String[] hashSplit = currentUrl.split("#");
if(hashSplit.length == 2) {
hash = hashSplit[1];
}
} else {
Intent intent = getActivity().getIntent();
if(intent != null && intent.getBooleanExtra(EXTRA_FROM_NOTIFICATION, false)) {
hash = "notification-launch";
}
}
if(hash.equals("notification-launch")) {
bgColor = Color.parseColor("#1abc9c");
} else if(hash.equals("notification-shown")) {
bgColor = Color.parseColor("#3498db");
} else if(hash.equals("secret")) {
bgColor = Color.parseColor("#34495e");
} else {
bgColor = Color.parseColor("#f1c40f");
}
preventBGColorFlicker(bgColor);
// We set the WebViewClient to ensure links are consumed by the WebView rather
// than passed to a browser if it can
mWebView.setWebViewClient(new WebViewClient());
return "file:///android_asset/www/index.html#"+hash;
}
/**
* This is a little bit of trickery to make the background color of the UI
* the same as the anticipated UI background color of the web-app.
*
* @param bgColor
*/
private void preventBGColorFlicker(int bgColor) {
((ViewGroup) getActivity().findViewById(R.id.activity_main_container)).setBackgroundColor(bgColor);
mWebView.setBackgroundColor(bgColor);
}
/**
* This method is designed to hide how Javascript is injected into
* the WebView.
*
* In KitKat the new evaluateJavascript method has the ability to
* give you access to any return values via the ValueCallback object.
*
* The String passed into onReceiveValue() is a JSON string, so if you
* execute a javascript method which return a javascript object, you can
* parse it as valid JSON. If the method returns a primitive value, it
* will be a valid JSON object, but you should use the setLenient method
* to true and then you can use peek() to test what kind of object it is,
*
* @param javascript
*/
public void loadJavascript(String javascript) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// In KitKat+ you should use the evaluateJavascript method
mWebView.evaluateJavascript(javascript, new ValueCallback<String>() {
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onReceiveValue(String s) {
JsonReader reader = new JsonReader(new StringReader(s));
// Must set lenient to parse single values
reader.setLenient(true);
try {
if(reader.peek() != JsonToken.NULL) {
if(reader.peek() == JsonToken.STRING) {
String msg = reader.nextString();
if(msg != null) {
Toast.makeText(getActivity().getApplicationContext(),
msg, Toast.LENGTH_LONG).show();
}
}
}
} catch (IOException e) {
Log.e("TAG", "MainActivity: IOException", e);
} finally {
try {
reader.close();
} catch (IOException e) {
// NOOP
}
}
}
});
} else {
/**
* For pre-KitKat+ you should use loadUrl("javascript:<JS Code Here>");
* To then call back to Java you would need to use addJavascriptInterface()
* and have your JS call the interface
**/
mWebView.loadUrl("javascript:"+javascript);
}
}
public boolean goBack() {
if(!mWebView.canGoBack()) {
return false;
}
mWebView.goBack();
return true;
}
}